/********************************************************************
	created:	2005/12/09 0:18
	filename: 	D:\DAPV4\user.cpp
	file path:	D:\DAPV4
	file base:	user
	file ext:	cpp
	author:		Albert Gu
	
	purpose:	Implement
*********************************************************************/
#ifndef _LINUX_OS_
#include "stdafx.h"
#endif
#include "TokenizerEx.h"
#include "user.h"
#include "MarkupSTL.h"

//////////////////////////////////////////////////////////////////////////
//Implement CDAPUser
CDAPUser::CDAPUser(USERID usrid, LPCTSTR lpszName)
{
	m_authBrowse = m_authConfig = m_authOperate = 0;
	m_usrId = usrid;
	m_bUseGroupAuth = false;
	m_szPesudoPt = "";
	m_nAckLv = 0;
	m_managerId=0xFFFF;
}
CDAPUser::CDAPUser(USERID usrid, LPCTSTR lpszName, LPCTSTR lpszPassword, LPCTSTR lpszMail /* = NULL */, 
				   USERID manid /* = NULL */, LPCTSTR lpszTel /* = NULL */, 
				   LPCTSTR lpszMobile /* = NULL */, LPCTSTR lpszDec /* = NULL */)
{
	assert(lpszName);
	assert(lpszPassword);
	m_szName = lpszName;
	m_szPassword = lpszPassword;
	if(lpszTel) m_szTel = lpszTel;
	if(lpszMobile) m_szMobile =lpszMobile;
	if(lpszDec) m_szDes = lpszDec;
	m_authBrowse = m_authConfig = m_authOperate = 0;
	m_usrId = usrid;
	m_managerId=manid;
	m_bUseGroupAuth = false;
	m_szPesudoPt = "";
	m_nAckLv = 0;
}

CDAPUser::CDAPUser(USERID usrid, LPCTSTR lpszName, AUTHID cfID, AUTHID optID, AUTHID bsID, 
				   LPCTSTR lpszPassword)
{
	assert(lpszName);
	m_szName = lpszName;
	m_szPassword = lpszPassword;
	m_authConfig = cfID;
	m_authOperate = optID;
	m_authBrowse = bsID;
	m_usrId = usrid;
	m_managerId=0xFFFF;
	m_bUseGroupAuth = false;
	m_szPesudoPt = "";
	m_nAckLv = 0;
}
//////////////////////////////////////////////////////////////////////////
void CDAPUser::SetUserInfo(LPCTSTR lpszMail /* = NULL */, 
					  USERID manid /* = NULL */, LPCTSTR lpszTel /* = NULL */, 
					  LPCTSTR lpszMobile /* = NULL */, LPCTSTR lpszDec /* = NULL */)
{
	if(lpszMail) m_szMail = lpszMail;
	if(lpszTel) m_szTel = lpszTel;
	if(lpszMobile) m_szMobile = lpszMobile;
	if(lpszDec) m_szDes = lpszDec;
	m_managerId=manid;
}

ostream& operator<<(ostream& os, const CDAPUser& obj)
{
	CMarkupSTL xml;
	xml.AddElem("user");
	xml.AddChildElem("id",(int)obj.m_usrId);
	xml.AddChildAttrib("name", obj.m_szName.c_str());
	xml.AddChildAttrib("groupauth", obj.m_bUseGroupAuth ? 1 : 0);
	xml.AddChildElem("pwd",obj.m_szPassword.c_str());
	xml.AddChildElem("email",obj.m_szMail.c_str());
	xml.AddChildElem("manid",(int)obj.m_managerId);
	xml.AddChildElem("tel",obj.m_szTel.c_str());
	xml.AddChildElem("mobile",obj.m_szMobile.c_str());
	xml.AddChildElem("description",obj.m_szDes.c_str());
	xml.AddChildElem("acklv", obj.m_nAckLv);
	xml.AddChildElem("priv_browse",(int)obj.m_authBrowse);
	xml.AddChildElem("priv_operate",(int)obj.m_authOperate);
	xml.AddChildElem("priv_config",(int)obj.m_authConfig);
	xml.AddChildElem("pesudopt", obj.m_szPesudoPt.c_str());
	os << xml.GetDoc();
	return os;
}

istringstream& operator>>(istringstream& stream, CDAPUser& obj)
{
	CMarkupSTL xml;
	xml.SetDoc(stream.str().c_str());
	if (xml.FindElem("user"))
	{
		xml.FindChildElem("id");
		obj.m_usrId = (USERID)atoi(xml.GetChildData().c_str());
		obj.m_szName = xml.GetChildAttrib("name");
		obj.m_bUseGroupAuth = atoi(xml.GetChildAttrib("groupauth").c_str()) != 0;
		xml.FindChildElem("pwd");
		obj.m_szPassword = xml.GetChildData();
		xml.FindChildElem("email");
		obj.m_szMail = xml.GetChildData();
		if(xml.FindChildElem("manid"))
			obj.m_managerId = (USERID)atoi(xml.GetChildData().c_str());
		else
			obj.m_managerId =0xFFFF;
		xml.FindChildElem("tel");
		obj.m_szTel = xml.GetChildData();
		xml.FindChildElem("mobile");
		obj.m_szMobile = xml.GetChildData();
		xml.FindChildElem("description");
		obj.m_szDes = xml.GetChildData();
		xml.FindChildElem("acklv");
		obj.m_nAckLv = atoi(xml.GetChildData().c_str());
		xml.FindChildElem("priv_browse");
		obj.m_authBrowse = (AUTHID)atol(xml.GetChildData().c_str());
		xml.FindChildElem("priv_operate");
		obj.m_authOperate = (AUTHID)atol(xml.GetChildData().c_str());
		xml.FindChildElem("priv_config");
		obj.m_authConfig = (AUTHID)atol(xml.GetChildData().c_str());
		if (xml.FindChildElem("pesudopt"))
			obj.m_szPesudoPt = xml.GetChildData();
		xml.RemoveNode();
		stream.str(xml.GetDoc());
	}
	return stream;
}

bool CDAPUser::VerifyPassword(LPCTSTR lpszPassword)
{
	if (!lpszPassword) return false;
	return m_szPassword.compare(lpszPassword) == 0;
}
/********************************************************************
    set User authority way return old way
*********************************************************************/
bool CDAPUser::UseGroupAuth(bool bUse)
{
	bool btemp = m_bUseGroupAuth;
	if (btemp != bUse)
		m_bUseGroupAuth = bUse;
	return btemp;
}

//////////////////////////////////////////////////////////////////////////
//Implement CDAPUserGroup
CDAPUserGroup::CDAPUserGroup(USERGROUPID gId, LPCTSTR lpszName, LPCTSTR lpszDesc)
{
	assert(lpszName);
	assert(lpszDesc);
	m_authGrpBrowse = m_authGrpConfig = m_authGrpOperate = 0;
	m_szGrpName = lpszName;
	m_szGrpDesc = lpszDesc;
	m_grpId = gId;
}

CDAPUserGroup::CDAPUserGroup(USERGROUPID gId, LPCTSTR lpszName, LPCTSTR lpszDesc, AUTHID cfID, AUTHID optID, AUTHID bsID)
{
	assert(lpszName);
	assert(lpszDesc);
	m_szGrpName = lpszName;
	m_szGrpDesc = lpszDesc;
	m_grpId = gId;
	m_authGrpConfig = cfID;
	m_authGrpOperate = optID;
	m_authGrpBrowse = bsID;
}

CDAPUserGroup::~CDAPUserGroup()
{
}
//////////////////////////////////////////////////////////////////////////
void CDAPUserGroup::SetGrpName(LPCTSTR lpszName)
{
	assert(lpszName);
	m_szGrpName = lpszName;
}

bool CDAPUserGroup::Add(USERID usrid)
{
	return insert(usrid).second;
}

void CDAPUserGroup::Remove(USERID usrid)
{
	erase(usrid);
}

bool CDAPUserGroup::IsExistUser(USERID usrid) const
{
	if (find(usrid) != end())
		return true;
	return false;
}

void CDAPUserGroup::SetGrpInfo(LPCTSTR lpszDesc)
{
	if (lpszDesc)
		m_szGrpDesc = lpszDesc;
}

ostream& operator<<(ostream& os, const CDAPUserGroup& obj)
{
	CMarkupSTL xml;
	xml.AddElem("group");
	xml.AddChildElem("id", (USERGROUPID)obj.m_grpId);
	xml.AddChildAttrib("name", obj.m_szGrpName.c_str());
	xml.AddChildElem("description", obj.m_szGrpDesc.c_str());
	xml.AddChildElem("priv_browse",(AUTHID)obj.m_authGrpBrowse);
	xml.AddChildElem("priv_operate",(AUTHID)obj.m_authGrpOperate);
	xml.AddChildElem("priv_config",(AUTHID)obj.m_authGrpConfig);
	ostringstream usros;
	set<USERID>::const_iterator pos = obj.begin();
	while(pos != obj.end())
		usros << *pos++ << ",";
	string szUsrID = usros.str();
	TrimRight(szUsrID, ',');
	xml.AddChildElem("owner", szUsrID.c_str());
	os << xml.GetDoc();
	return os;
}

istringstream& operator>>(istringstream& stream, CDAPUserGroup& obj)
{
	CMarkupSTL xml;
	xml.SetDoc(stream.str().c_str());
	if (xml.FindElem("group"))
	{
		xml.FindChildElem("id");
		obj.m_grpId = (USERGROUPID)atoi(xml.GetChildData().c_str());
		obj.m_szGrpName = xml.GetChildAttrib("name");
		xml.FindChildElem("description");
		obj.m_szGrpDesc = xml.GetChildData();
		xml.FindChildElem("priv_browse");
		obj.m_authGrpBrowse = (AUTHID)atol(xml.GetChildData().c_str());
		xml.FindChildElem("priv_operate");
		obj.m_authGrpOperate = (AUTHID)atol(xml.GetChildData().c_str());
		xml.FindChildElem("priv_config");
		obj.m_authGrpConfig = (AUTHID)atol(xml.GetChildData().c_str());
		if (xml.FindChildElem("owner"))
		{
			vector<string>vecUser;
			string szUsrs = xml.GetChildData();
			CTokenizer<CIsFromString>::Tokenize(vecUser, szUsrs, CIsFromString(","));
			for (int i = 0; i < vecUser.size(); i++)
				if (!vecUser[i].empty())
					obj.insert((USERID)atoi(vecUser[i].c_str()));
		}
		xml.RemoveNode();
		stream.str(xml.GetDoc());
	}
	return stream;
}
//////////////////////////////////////////////////////////////////////////
//Implement CDAPUserManage
CDAPUserManage::~CDAPUserManage()
{
	RemoveAll();
}
//////////////////////////////////////////////////////////////////////////
ostream& operator<<(ostream& os, const CDAPUserManage& obj)
{
	CMarkupSTL xml;
	xml.AddElem("dapuserunit");
	ostringstream tmpos;
	USERMAP::const_iterator pos = obj.m_userMap.begin();
	while(pos != obj.m_userMap.end())
	{
		tmpos << *(pos->second);
		xml.AddChildSubDoc(tmpos.str().c_str());
		tmpos.str("");
		++pos;
	}
	USERGROUPMAP::const_iterator gpos = obj.m_grpMap.begin();
	while(gpos != obj.m_grpMap.end())
	{
		tmpos << *(gpos->second);
		xml.AddChildSubDoc(tmpos.str().c_str());
		tmpos.str("");
		++gpos;
	}
	os << xml.GetDoc();
	return os;
}

istream& operator>>(istream& stream, CDAPUserManage& obj)
{
	obj.RemoveAll();
	ostringstream os;
	os << stream.rdbuf();
	CMarkupSTL xml;
	xml.SetDoc(os.str().c_str());
	if (xml.FindElem("dapuserunit"))
	{
		istringstream tmpis;
		while(xml.FindChildElem("user"))
		{
			tmpis.str(xml.GetChildSubDoc());
			CDAPUser* pUser = new CDAPUser;
			assert(pUser);
			tmpis >> *pUser;
			if(!obj.Add(pUser))
				delete pUser;
		}
		xml.ResetMainPos();
		while(xml.FindChildElem("group"))
		{
			tmpis.str(xml.GetChildSubDoc());
			CDAPUserGroup* pGroup = new CDAPUserGroup;
			assert(pGroup);
			tmpis >> *pGroup;
			if(!obj.Add(pGroup))
				delete pGroup;
		}
	}
	return stream;
}

CDAPUserGroup* CDAPUserManage::GetGrp(USERGROUPID gId)
{
	USERGROUPMAP::iterator pos = m_grpMap.find(gId);
	if (pos != m_grpMap.end())
		return pos->second;
	return NULL;
}

CDAPUser* CDAPUserManage::GetUser(USERID usrid)
{
	USERMAP::iterator pos = m_userMap.find(usrid);
	if (pos != m_userMap.end())
		return pos->second;
	return NULL;
}

void CDAPUserManage::RemoveGroup(USERGROUPID gId)
{
	if (gId == (USERGROUPID)0) return;
	USERGROUPMAP::iterator pos = m_grpMap.find(gId);
	if (pos != m_grpMap.end())
	{
		CDAPUserGroup* pGroup = pos->second;
		m_NameMap.erase(pGroup->GetGrpName());
		delete pGroup;
		m_grpMap.erase(pos);
		m_bModified = true;
	}
}

void CDAPUserManage::RemoveUser(USERID usrid)
{
	if (usrid == (USERID)0) return;
	USERGROUPMAP::iterator pos = m_grpMap.begin();
	while(pos != m_grpMap.end())
	{
		CDAPUserGroup* pGroup = pos->second;
		pGroup->Remove(usrid);
		++pos;
	}
	USERMAP::iterator usrpos = m_userMap.find(usrid);
	if (usrpos != m_userMap.end())
	{
		CDAPUser* pUser = usrpos->second;
		assert(pUser);
		m_NameMap.erase(pUser->GetUserName());
		delete pUser;
		m_userMap.erase(usrpos);
		m_bModified = true;
	}
}

void CDAPUserManage::RemoveAll()
{
	Logout();
	if (!m_grpMap.empty())
	{
		USERGROUPMAP::iterator pos = m_grpMap.begin();
		while(pos != m_grpMap.end())
		{
			delete pos->second;
			++pos;
		}
		m_grpMap.clear();
	}
	if (!m_userMap.empty())
	{
		USERMAP::iterator pos = m_userMap.begin();
		while(pos != m_userMap.end())
		{
			delete pos->second;
			++pos;
		}
		m_userMap.clear();
	}
	m_NameMap.clear();
}


int CDAPUserManage::GetFreeUserID()
{
	for (int i = 1; i < 0x0ffff; i++)
	{
		if (m_userMap.find((USERID)i) != m_userMap.end())
			continue;
		else
			return i;
	}
	return -1;
}

int CDAPUserManage::GetFreeGrpID()
{
	for (int i = 1; i < 0x0ffff; i++)
	{
		if (m_grpMap.find((USERGROUPID)i) != m_grpMap.end())
			continue;
		else
			return i;
	}
	return -1;
}

bool CDAPUserManage::Add(CDAPUser* pUser)
{
	if (!pUser) return false;
	if (m_NameMap.find(pUser->GetUserName())!= m_NameMap.end())
		return false;
	if (m_userMap.insert(make_pair(pUser->GetUserID(), pUser)).second)
	{
		m_NameMap.insert(pUser->GetUserName());
		m_bModified = true;
		return true;
	}
	return false;
}

bool CDAPUserManage::Add(CDAPUserGroup* pGroup)
{
	if (!pGroup) return false;
	if (m_NameMap.find(pGroup->GetGrpName())!= m_NameMap.end())
		return false;
	if (m_grpMap.insert(make_pair(pGroup->GetGrpId(), pGroup)).second)
	{
		m_NameMap.insert(pGroup->GetGrpName());
		m_bModified = true;
		return true;
	}
	return false;
}

/********************************************************************
    this function is only called when create new DAP Project
*********************************************************************/
bool CDAPUserManage::CreateSuperUser()
{
	if (m_userMap.size() > 0 || m_idLoginUser != (USERID)-1) return false;
	CDAPUser* pUser = new CDAPUser(0, "admin", CONFIG_ALL, OPT_ALL, WINBROWSE_ALL,"cdpp08");
	if (!pUser) return false;
	Add(pUser);
	CDAPUserGroup* pGroup = new CDAPUserGroup(0, "admins", "Administrator", CONFIG_ALL, OPT_ALL, WINBROWSE_ALL);
	if (!pGroup) return false;
	Add(pGroup);
	if(!pGroup->Add((USERID)0)) return false;
	m_bModified = true;
	return true;
}

bool CDAPUserManage::Login(USERID usrid, USERGROUPID gId, LPCTSTR szPasswd)
{
	if ((USERGROUPID)-1 != gId)
	{
		const CDAPUserGroup* pGroup = GetGrp(gId);
		if (!pGroup) return false;
		if (!pGroup->IsExistUser(usrid)) return false;
	}
	CDAPUser* pUser = GetUser(usrid);
	if (!pUser) return false;
	if (!pUser->VerifyPassword(szPasswd)) return false;
	m_idLoginGrp = gId;
	m_idLoginUser = usrid;
	return true;
}


bool CDAPUserManage::CheckCfgAccess(ACS acs)
{
	if (m_idLoginUser == (USERID)-1) return false;
	const CDAPUser* pUser = GetUser(m_idLoginUser);
	assert(pUser);
	if (pUser->IsUseGroupAuth() && m_idLoginGrp != (USERGROUPID)-1)
	{
		if (m_idLoginGrp == (USERGROUPID)-1) return false;
		const CDAPUserGroup* pGroup = GetGrp(m_idLoginGrp);
		assert(pGroup);
		return pGroup->CheckCfgAccess(acs);
	}
	return pUser->CheckCfgAccess(acs);
}

bool CDAPUserManage::CheckOptAccess(ACS acs)
{
	if (m_idLoginUser == (USERID)-1) return false;
	CDAPUser* pUser = GetUser(m_idLoginUser);
	assert(pUser);
	if (pUser->IsUseGroupAuth() && m_idLoginGrp != (USERGROUPID)-1)
	{
		if (m_idLoginGrp == (USERGROUPID)-1) return false;
		CDAPUserGroup* pGroup = GetGrp(m_idLoginGrp);
		assert(pGroup);
		return pGroup->CheckOptAccess(acs);
	}
	return pUser->CheckOptAccess(acs);
}

bool CDAPUserManage::Save(LPCTSTR lpszPath)
{
	assert(lpszPath);
	ofstream file(lpszPath);
	if (!file) return false;
	file << *this;
	m_bModified = false;
	return file.good();
}

bool CDAPUserManage::Load(LPCTSTR lpszPath)
{
	assert(lpszPath);
	ifstream file(lpszPath);
	if (!file) return false;
	file >> *this;
	m_bModified = false;
	return file.good();
}

bool CDAPUserManage::CheckName(LPCTSTR lpszName)
{
	assert(lpszName);
	return m_NameMap.find(string(lpszName)) != m_NameMap.end();
}

bool CDAPUserManage::IsValid()
{
	return m_userMap.size() > 0 && NULL != GetUser(0);
}
